use windows::core::{ComInterface, HSTRING};
use windows::Devices::Enumeration::DeviceInformation;
use crate::define::*;
use regex::Regex;
use async_trait::async_trait;
use log::*;
use windows::Devices::Usb::*;
use windows::Devices::Usb;
use windows::{Foundation::*, Win32::System::WinRT::IMemoryBufferByteAccess};
use windows::Storage::Streams::{Buffer, DataReader};
use crate::define;
use crate::define::UsbError::Unknown;
use crate::os::windows::interface::OsInterface;

#[derive(Default, Debug)]
pub(crate) struct OsDevice{
    vid: u64,
    pid: u64,
    name: String,
    id: HSTRING,
    ctx: Option<UsbDevice>
}

fn get_id_num(re: Regex, text: &str)->u64{
    let mut id = 0u64;

    for caps in re.captures_iter(text) {
        let vid_str  = caps.get(1);
        match &vid_str {
            None => {}
            Some(vid_str) => {
                let vid_str = vid_str.as_str();
                match u64::from_str_radix(vid_str, 16) {
                    Ok(i) => {id = i}
                    Err(_) => {}
                }
            }
        }
    }
    id
}
unsafe fn as_mut_slice(buffer: &IMemoryBufferReference) -> MResult<&mut [u8]> {
    let interop = buffer.cast::<IMemoryBufferByteAccess>()?;
    let mut data = std::ptr::null_mut();
    let mut len = 0;

    interop.GetBuffer(&mut data, &mut len)?;
    Ok(std::slice::from_raw_parts_mut(data, len as _))
}
fn slice_to_buffer(data: &[u8])-> MResult<Buffer>{
    let length = data.len() as u32;
    let buffer = MemoryBuffer::Create(length)?;
    let reference = buffer.CreateReference()?;
    // Write to buffer...

    let slice = unsafe { as_mut_slice(&reference)? };
    slice.copy_from_slice(data);

    let buffer = Buffer::CreateCopyFromMemoryBuffer(&buffer)?;
    buffer.SetLength(length)?;
    Ok(buffer)
}


impl OsDevice{

    fn set_id(&mut self, id: HSTRING){
        let text = (&id).to_string_lossy();
        self.id = id;
        let  regex_id_vid = Regex::new(r"VID_([0-9A-Fa-f]+)").unwrap();
        let  regex_id_pid = Regex::new(r"PID_([0-9A-Fa-f]+)").unwrap();
        self.vid = get_id_num(regex_id_vid, &text);
        self.pid = get_id_num(regex_id_pid, &text);
    }

}

impl TryFrom<DeviceInformation> for OsDevice{
    type Error = UsbError;

    fn try_from(value: DeviceInformation) -> std::result::Result<Self, Self::Error> {
        let name = value.Name()?;
        let mut d = OsDevice::default();
        d.name = name.to_string_lossy();
        d.set_id(value.Id()?);
        Ok(d)
    }
}


fn get_packet(request: &ControlTransferRequest, direction: UsbTransferDirection)->MResult<UsbSetupPacket>{

    let packet = UsbSetupPacket::new()?;
    let request_type = Usb::UsbControlRequestType::new()?;
    request_type.SetDirection(direction)?;
    request_type.SetRecipient(match request.request_type.recipient{
        define::UsbControlRecipient::Device => Usb::UsbControlRecipient::Device,
        define::UsbControlRecipient::SpecifiedInterface => Usb::UsbControlRecipient::SpecifiedInterface,
        define::UsbControlRecipient::Endpoint => Usb::UsbControlRecipient::Endpoint,
        define::UsbControlRecipient::Other => Usb::UsbControlRecipient::Other,
        define::UsbControlRecipient::DefaultInterface => Usb::UsbControlRecipient::DefaultInterface,
    })?;
    request_type.SetControlTransferType(match request.request_type.control_transfer_type {
        define::UsbControlTransferType::Standard => Usb::UsbControlTransferType::Standard,
        define::UsbControlTransferType::Class => Usb::UsbControlTransferType::Class,
        define::UsbControlTransferType::Vendor => Usb::UsbControlTransferType::Vendor,
    })?;
    packet.SetRequestType(&request_type)?;
    packet.SetRequest(request.request)?;
    packet.SetValue(request.value as u32)?;
    packet.SetIndex(request.index as u32)?;
    packet.SetLength(request.data.len() as u32)?;
    if request.len>0{
        packet.SetLength(request.len)?;
    }

    Ok(packet)
}

#[async_trait]
impl Device for OsDevice {
    fn get_vid(&self) -> u64 {
        self.vid
    }

    fn get_pid(&self) -> u64 {
        self.pid
    }

    fn get_name(&self) -> String {
        self.name.clone()
    }

    async fn open(&mut self)-> MResult<()> {
        let ctx = UsbDevice::FromIdAsync(&self.id)?.await?;
        debug!("USB version: {}", ctx.DeviceDescriptor()?.BcdDeviceRevision()?);
        debug!("USB speed: {}", ctx.DeviceDescriptor()?.BcdUsb()?);
        self.ctx = Some(ctx);
        Ok(())
    }


    async fn control_transfer_in(&self, request: ControlTransferRequest) -> MResult<Vec<u8>> {
        return match &self.ctx {
            None => { Err(Unknown(format!("[{}]未打开", self.name))) }
            Some(ctx) => {
                let packet = get_packet(&request, UsbTransferDirection::In)?;

                let buffer = if request.len == 0 {
                    ctx.SendControlInTransferAsyncNoBuffer(&packet)?.await?
                } else {
                    let buf = Buffer::Create(request.len)?;
                    buf.SetLength(request.len)?;
                    ctx.SendControlInTransferAsync(&packet, &buf)?.await?
                };
                let length = buffer.Length()? as usize;
                let reader = DataReader::FromBuffer(&buffer)?;
                let mut out = vec![0; length];
                reader.ReadBytes(out.as_mut_slice())?;
                Ok(out)
            }
        }
    }

    async fn control_transfer_out(&self, request: ControlTransferRequest) -> MResult<usize> {
        return match &self.ctx {
            None => { Err(Unknown(format!("[{}]未打开", self.name))) }
            Some(ctx) => {
                let no_data = request.data.is_empty();
                let packet = get_packet(&request, UsbTransferDirection::Out)?;
                let n = if no_data {
                    ctx.SendControlOutTransferAsyncNoBuffer(&packet)?.await?
                } else {
                    let buf = slice_to_buffer(&request.data)?;
                    ctx.SendControlOutTransferAsync(&packet, &buf)?.await?
                };
                Ok(n as usize)
            }
        }
    }

    fn interface_count(&self) -> MResult<usize> {
        match &self.ctx {
            None => { Err(Unknown(format!("[{}]未打开", self.name))) }
            Some(ctx) => {
                let list = ctx.Configuration()?.UsbInterfaces()?;
                Ok(list.Size()? as _)
            }
        }
    }

    fn interface_get(&self, index: usize) -> MResult<Box<dyn define::UsbInterface>> {
        match &self.ctx {
            None => { Err(Unknown(format!("[{}]未打开", self.name))) }
            Some(ctx) => {
                let list = ctx.Configuration()?.UsbInterfaces()?;
                let one = list.GetAt(index as _)?;
                Ok(Box::new(OsInterface::from(one) ))
            }
        }
    }

    fn interface_default(&self) -> MResult<Box<dyn define::UsbInterface>> {
        match &self.ctx {
            None => { Err(Unknown(format!("[{}]未打开", self.name))) }
            Some(ctx) => {
                let one = ctx.DefaultInterface()?;
                Ok(Box::new(OsInterface::from(one) ))
            }
        }
    }
}

impl Drop for OsDevice {
    fn drop(&mut self) {
        match &self.ctx {
            None => {}
            Some(g) => {
                debug!("[{}]关闭", self.name);
                let _ = g.Close();
            }
        }
    }
}




#[cfg(test)]
mod tests {
    use log::{info, LevelFilter};
    use super::*;
    fn init() {
        let _ = env_logger::builder().filter_level(LevelFilter::Debug).is_test(true).try_init();
    }

    #[tokio::test]
    async fn it_works() {
        init();

        let mut device = OsDevice::default();
        device.set_id(HSTRING::from("\\\\?\\USB#VID_1D50&PID_6089#0000000000000000a8b067d2263359e7#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"));


        info!("{:?}", device);
    }
}
